/*
 * FeuSignalisationTramway.cpp
 *
 *  Created on: 17 mars 2011
 *      Author: nico
 */

#include "FeuSignalisationTramway.h"

//-----------------------------------------------------------------------------
// Prototypes de fonctions de global.cpp
//-----------------------------------------------------------------------------
void ajouterThread(pthread_t thread, int type_thread);
int getNbThreads(int typeThread);
pthread_t* getRame(int numero);
//------

// Crée un nouveau feu de signalisation
FeuSignalisationTramway::FeuSignalisationTramway() {
	this->passageAutorise = true;
	cout << "Nouveau feu de signalisation pour Tramway créé avec aucun état prédéfini => Passage autorisé" << endl;
}

// Créé un nouveau feu de signalisation avec un état passé en
// paramètre
FeuSignalisationTramway::FeuSignalisationTramway(bool passageAutorise) {
	this->passageAutorise = passageAutorise;
	cout << "Nouveau feu de signalisation pour Tramway créé à l'état : " << flush;
	if(passageAutorise) {
		cout << "Passage autorisé" << endl;
	}
	else {
		cout << "Passage non autorisé" << endl;
	}
}

void FeuSignalisationTramway::demarrerThread() {
	if (pthread_create(&thread, 0, FeuSignalisationTramway::threadFeuSignalisationTramway, this) != 0) {
		cout << "/!\\ Echec dans fonction FeuSignalisationTramway::demarrerThread. /!\\" << endl;
	}
	else {
		cout << "Thread FeuSignalisationTramway créé" << endl;
	}
	ajouterThread(this->thread, FEU_SIGNALISATION);
}

void * FeuSignalisationTramway::threadFeuSignalisationTramway(void * param) {
	sigset_t signal;
	int sigIntercepte;

	// On s'assure que le masque de signaux est vide
	if(sigemptyset(&signal) == -1) {
		perror("Erreur sigemptyset");
	}

	// On ajoute le signal SIGUSR1 au masque
	if(sigaddset(&signal, SIGUSR1) == -1) {
		perror("Erreur sigaddset");
	}

	while(1) {
		// On récupère le pointeur sur le feu passé en paramètre de création du thread
		FeuSignalisationTramway * fst = reinterpret_cast<FeuSignalisationTramway*>(param);

		// On attend que le signal SIGUSR1 se présente, qui aura pour conséquence
		// de changer l'état du feu
		sigwait(&signal, &sigIntercepte);
		if(sigIntercepte == SIGUSR1) {
			if(fst->passageEstAutorise()) {
				fst->setPassageAutorise(false);
			}
			else {
				fst->setPassageAutorise(true);
			}
		}
	}

	return 0;
}


// Retourne l'état actuel du feu de signalisation
bool FeuSignalisationTramway::passageEstAutorise() const {
	return this->passageAutorise;
}

// Modifie l'état du feu de signalisation par celui passé en paramètre
void FeuSignalisationTramway::setPassageAutorise(bool passageAutorise) {
	this->passageAutorise = passageAutorise;
	cout << "Changement d'état du feu de signalisation demandé..." << passageAutorise << endl;
	// Envoi du signal afin de signaler le changement d'état du feu
	for(int r=0 ; r<getNbThreads(RAME) ; r++) {
		cout << "Rame " << r << " : " << getRame(r) << endl;
		if(this->passageAutorise) {
			cout << "SIGUSR1 envoyé depuis le feu." << endl;
			pthread_kill(*getRame(r), SIGUSR1);
		}
		else {
			cout << "SIGUSR2 envoyé depuis le feu." << endl;
			pthread_kill(*getRame(r), SIGUSR2);
		}
	}
}

// Modifie l'état du feu de signalisation en un état généré aléatoirement
void FeuSignalisationTramway::setPassageAutoriseAleatoire() {
	// TODO A faire
}

FeuSignalisationTramway::~FeuSignalisationTramway() {

}


